from sys import argv
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

class MyPyOpenGLTest:
    def __init__(self, width=640, height=480, title='三次Bezier曲面'):
        glutInit(len(argv), argv)
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
        glutInitWindowSize(width, height)
        glutInitWindowPosition(350, 200)
        self.window = glutCreateWindow(title.encode('gbk'))
        glutDisplayFunc(self.draw)
        glutIdleFunc(self.draw)
        glutKeyboardFunc(self.key_press)
        glutSpecialFunc(self.spcial_key)
        
        glClearColor(1, 1, 1, 1)
        glEnable(GL_DEPTH_TEST)
        glShadeModel(GL_SMOOTH)
        glEnable(GL_POINT_SMOOTH)
        glEnable(GL_LINE_SMOOTH)
        glEnable(GL_POLYGON_SMOOTH)
        glHint(GL_POINT_SMOOTH_HINT,GL_NICEST)
        glHint(GL_LINE_SMOOTH_HINT,GL_NICEST)
        glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST)

        # 光源位置
        glLightfv(GL_LIGHT0, GL_POSITION, (0, -3, -10, 1))
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)

        glMaterialfv(GL_FRONT, GL_AMBIENT, (0.15, 0.23, 0.13))
        glMaterialfv(GL_FRONT, GL_DIFFUSE, (0.6, 0.2, 0.3))
        glMaterialfv(GL_FRONT, GL_SPECULAR, (0.71, 0.6, 0.73))

        glMaterialfv(GL_FRONT, GL_SHININESS, 10)
        
        glMatrixMode(GL_PROJECTION)
        glOrtho(-5, 5, -5, 5, -5, 5)
        # 指定三次贝塞尔曲面的16个控制点坐标
        self.control_points = (
            ((-2,-2,-4), (-1,-2,4), (1,-2,-4), (2,-2,-4)),
            ((-2,-1,-1), (-1,-1,-1), (1,-1,-1), (2,-1,-1)),
            ((-2,1,1), (-1,1,1), (1,1,1), (2,1,1)),
            ((-2,2,4), (-1,2,-4), (1,2,4), (2,2,4)))
        # 沿坐标轴旋转的角度
        self.angle_x = 0
        self.angle_y = 0
        self.angle_z = 0

        self.fill_or_line = GL_FILL
        self.un, self.vn = 30, 30

    def key_press(self, key, x, y):
        if key == b'a':
            self.angle_x = self.angle_x + 5
        elif key == b'z':
            self.angle_x = self.angle_x - 5
        elif key == b's':
            self.angle_y = self.angle_y + 5
        elif key == b'x':
            self.angle_y = self.angle_y - 5
        elif key == b'd':
            self.angle_z = self.angle_z + 5
        elif key == b'c':
            self.angle_z = self.angle_z - 5
        elif key == b' ':
            if self.fill_or_line == GL_LINE:
                self.fill_or_line = GL_FILL
            elif self.fill_or_line == GL_FILL:
                self.fill_or_line = GL_LINE
        else:
            return
        glutPostRedisplay()

    def spcial_key(self, key, x, y):
        if key == GLUT_KEY_UP:
            self.un = min(100, self.un+1)
        elif key == GLUT_KEY_DOWN:
            self.un = max(1, self.un-1)
        elif key == GLUT_KEY_RIGHT:
            self.vn = min(100, self.vn+1)
        elif key == GLUT_KEY_LEFT:
            self.vn = max(1, self.vn-1)
        else:
            return
        glutPostRedisplay()
    
    def draw(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        glMap2f(GL_MAP2_VERTEX_3, 0, 1, 0, 1, self.control_points)

        glEnable(GL_MAP2_VERTEX_3)
        glEnable(GL_AUTO_NORMAL)

        glRotate(self.angle_x, 1, 0, 0)
        glRotate(self.angle_y, 0, 1, 0)
        glRotate(self.angle_z, 0, 0, 1)
        glColor3f(0, 0, 0)

        glMapGrid2f(self.un, 0, 1, self.vn, 0, 1)
        glEvalMesh2(self.fill_or_line, 0, self.un, 0, self.vn)
        
        glutSwapBuffers()

    # 消息主循环
    def mainloop(self):
        glutMainLoop()

if __name__ == '__main__':
    MyPyOpenGLTest().mainloop()
